package com.yingxin.yxerp.module.oplog.aop.submit;

import cn.hutool.crypto.digest.DigestUtil;
import com.alibaba.fastjson.JSONObject;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.yingxin.yx.framework.commons.exception.BizException;
import com.yingxin.yx.framework.user.core.IUserSupport;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @author fanchao
 */
@Data
@Aspect
@Configuration
public class LocalLockMethodInterceptor {

    @Autowired
    private IUserSupport userSupport;

    @Value("${spring.profiles}")
    private String springProfilesActive;

    @Value("${spring.application.name}")
    private String springApplicationName;

    private static int expireTimeSecond =5;

    @Value("${resubmit.local.timeOut}")
    public void setExpireTimeSecond(int expireTimeSecond) {
        LocalLockMethodInterceptor.expireTimeSecond = expireTimeSecond;
    }

    //定义缓存，设置最大缓存数及过期日期
    private static final Cache<String,Object> CACHE =
            CacheBuilder.newBuilder().maximumSize(1000).expireAfterWrite(expireTimeSecond, TimeUnit.SECONDS).build();

    @Around("execution(public * *(..))  && @annotation(com.yingxin.yxerp.module.oplog.aop.submit.LocalLock)")
    public Object interceptor(ProceedingJoinPoint joinPoint){

        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        // Method method = signature.getMethod();
        // LocalLock localLock = method.getAnnotation(LocalLock.class);
        try{
            String key = getLockUniqueKey(signature,joinPoint.getArgs());
            if(CACHE.getIfPresent(key) != null){
                throw new BizException("不允许重复提交，请稍后再试");
            }
            CACHE.put(key,key);
            return joinPoint.proceed();
        }catch (Throwable throwable){
            // throw new RuntimeException(throwable.getMessage());
            throw new BizException( throwable.getMessage() );
        }
    }

    /**
     * 获取唯一标识key
     */
    private String getLockUniqueKey(MethodSignature methodSignature, Object[] args) throws NoSuchAlgorithmException {
        //请求uri, 获取类名称，方法名称
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) requestAttributes;
        HttpServletRequest request = servletRequestAttributes.getRequest();
        // HttpServletResponse responese = servletRequestAttributes.getResponse();

        String hash = "";
        List list = new ArrayList();
        if (args.length > 0) {
            String[] parameterNames = methodSignature.getParameterNames();
            for (int i = 0; i < parameterNames.length; i++) {
                Object obj = args[i];
                list.add(obj);
            }
            hash = JSONObject.toJSONString(list);
        }
        //项目名称 + 环境编码 + 获取类名称 + 方法名称 + 唯一key
        String key = "locallock:" + springApplicationName + ":" + springProfilesActive + ":" + userSupport.getUserId();
        if (StringUtils.isNotEmpty(key)) {
            key = key + ":" + hash;
        }
        return DigestUtil.md5Hex(key);
    }

}